package com.oitsm.plugin.service;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.oitsm.plugin.entity.Meta;
import com.oitsm.plugin.entity.Option;
import com.oitsm.plugin.entity.PluginMeta;
import com.oitsm.plugin.entity.PropMeta;
import com.oitsm.plugin.entity.ResponseMeta;
import com.oitsm.utils.IOUtil;
import com.oitsm.utils.PropUtil;
/**
 * 
 * @author Arab Runner
 * Jul 30, 2011 5:12:02 PM
 */
public class PluginMetaService {
	public static Logger logger = Logger.getLogger(PluginMetaService.class.getName());
	private static Map<String,PluginMeta> pluginMetas = new HashMap<String,PluginMeta>();
	
	public static void init()throws Exception{
		File dir = new File(PropUtil.getPath("configs"));
		
		DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
		DocumentBuilder dombuilder = domfac.newDocumentBuilder();
		for(File fs : dir.listFiles()){
			if(fs.isDirectory()){
				continue;
			}
			
			if(!fs.getName().endsWith(".xml")){
				continue;
			}
			
			parseXML(dombuilder,fs);
		}
	}
	
	public static PluginMeta getPluginMeta(String name){
		return pluginMetas.get(name);
	}
	
	/**
	 * 解析XML文件
	 * @param dombuilder
	 * @param f
	 */
	@SuppressWarnings("unchecked")
	private static void parseXML(DocumentBuilder dombuilder,File f){
		FileInputStream is = null;
		try{
			is = new FileInputStream(f);
		    Document doc = dombuilder.parse(is);
		    Element root =  doc.getDocumentElement();
		    NodeList nodes = root.getChildNodes();
		    
		    Map<String,List> publics = new HashMap<String,List>();
		    
		    // parsing public
		    for(int i=0;i<nodes.getLength();i++){
		    	Node node = nodes.item(i);
		    	if("public".equals(node.getNodeName())){
		    		String type = getAttrValue(node,"type");
		    		String name = getAttrValue(node,"name");
		    		if(StringUtils.isEmpty(name) || !"prop".equals(type)){
		    			continue;
		    		}
		    		List<PropMeta> props = parsePropMetas(node,null);
	    			publics.put(name, props);
		    	}
		    }
		    
		    // parsing pulugin
		    for(int i=0;i<nodes.getLength();i++){
		    	Node pluginNode = nodes.item(i);
		    	//puglin
		    	if("plugin".equals(pluginNode.getNodeName())){
		    		String name = getAttrValue(pluginNode, "name");
		    		String excutor = getAttrValue(pluginNode, "excutor");
		    		if(StringUtils.isEmpty(name) || StringUtils.isEmpty(excutor)){
		    			continue;
		    		}
		    		
		    		PluginMeta p = new PluginMeta();
		    		p.setName(name);
		    		p.setExcutor(excutor);
		    		
		    		NodeList pluginAttrsNodes =  pluginNode.getChildNodes();
		    		for(int j=0;j<pluginAttrsNodes.getLength();j++){
		    			Node pluginAttrNode = pluginAttrsNodes.item(j);
		    			// props
		    			if("props".equals(pluginAttrNode.getNodeName())){
		    				List<PropMeta> props = parsePropMetas(pluginAttrNode,publics);
		    				p.setProps(props);
		    				
		    			}else if("responses".equals(pluginAttrNode.getNodeName())){
		    				List<ResponseMeta> responses = parseResponseMetas(pluginAttrNode);
		    				p.setResponses(responses);
		    			}else if("constants".equals(pluginAttrNode.getNodeName())){
		    				List<Meta> constants = parseMeta(pluginAttrNode);
		    				p.setConstants(constants);
		    			}
		    		}
		    		
		    		pluginMetas.put(p.getName(), p);
		    	}
		    }
		    
		}catch(Exception e){
			logger.error("parsed failure,plugin xml:"+f.getName());
		}finally{
			IOUtil.closeInputStream(is);
		}
	}
	
	/**
	 * 解析 response标签
	 * @param propsNode
	 * @return
	 */
	private static List<ResponseMeta> parseResponseMetas(Node propsNode){
		List<ResponseMeta> props = new ArrayList<ResponseMeta>();
		
		NodeList nodes = propsNode.getChildNodes();
		for(int i=0;i<nodes.getLength();i++){
			Node node = nodes.item(i);
			String name = getAttrValue(node,"name");
			if(StringUtils.isEmpty(name)){
				continue;
			}
			String label = getAttrValue(node,"label");
			String type = getAttrValue(node,"type");
			String unit = getAttrValue(node,"unit");
			String value = getAttrValue(node,"value");
			String formula = getAttrValue(node,"formula");
			boolean  isAbstract = "true".equals(getAttrValue(node,"abstract"));
			
			
			ResponseMeta m = new ResponseMeta(name,label,type,value,unit,formula,isAbstract);
			props.add(m);
		}
		return props;
	}
	
	/**
	 * 解析contonts标签
	 * @param propsNode
	 * @return
	 */
	private static List<Meta> parseMeta(Node propsNode){
		List<Meta> props = new ArrayList<Meta>();
		
		NodeList nodes = propsNode.getChildNodes();
		for(int i=0;i<nodes.getLength();i++){
			Node node = nodes.item(i);
			String name = getAttrValue(node,"name");
			if(StringUtils.isEmpty(name)){
				continue;
			}
			String label = getAttrValue(node,"label");
			String type = getAttrValue(node,"type");
			String value = getAttrValue(node,"value");
			
			Meta m = new Meta(name,label,type,value);
			props.add(m);
		}
		return props;
	}
	
	/**
	 * 解析prop
	 * @param propsNode
	 * @param publics
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static List<PropMeta> parsePropMetas(Node propsNode,Map<String,List> publics){
		List<PropMeta> props = new ArrayList<PropMeta>();
		
		NodeList nodes = propsNode.getChildNodes();
		for(int i=0;i<nodes.getLength();i++){
			Node node = nodes.item(i);
			String name = getAttrValue(node,"name");
			if(StringUtils.isEmpty(name)){
				continue;
			}
			if("meta".equals(node.getNodeName())){
				String label = getAttrValue(node,"label");
				String type = getAttrValue(node,"type");
				String options = getAttrValue(node,"options");
				String value = getAttrValue(node,"value");
				
				List<Option> optionsList = null;
				if(StringUtils.isNotEmpty(options)){
					optionsList = parseOption(options);
				}
				
				PropMeta m = new PropMeta(name,label,type,value,optionsList);
				props.add(m);
			}else if("refrence".equals(node.getNodeName())){
				List<PropMeta> rs = publics.get(name);
				if(rs!=null){
					props.addAll(rs);
				}
			}
		}
		return props;
	}
	
	/**
	 * 解析options
	 * @param options
	 * @return
	 */
	private static List<Option> parseOption(String options){
		List<Option> optionsList = new ArrayList<Option>();
		String[] optStrs = options.split(";");
		for(String optStr : optStrs){
			if(StringUtils.isEmpty(optStr)){
				continue;
			}
			
			String[] pair = optStr.split(",");
			if(pair == null || pair.length != 2){
				continue;
			}
			Option p = new Option(pair[0],pair[1]);
			optionsList.add(p);
		}
		if(optionsList.size() == 0){
			optionsList = null;
		}
		return optionsList;
	}
	
	// <xxxxx name="value"
	private static String getAttrValue(Node node,String name){
		if(node.getAttributes() == null){
			return null;
		}
		Node attrs = node.getAttributes().getNamedItem(name);
		return attrs==null?null:attrs.getNodeValue();
	}

	public Map<String, PluginMeta> getPluginMetas() {
		return pluginMetas;
	}
	
	public static void main(String[] args) throws Exception{
		init();
	}
}
